import type {
  CreateCrudOptionsProps,
  CreateCrudOptionsRet,
  CrudExpose,
  ScopeContext,
  ValueBuilderContext,
  ValueResolveContext,
} from '@fast-crud/fast-crud';

import type { FormRulesExt } from '#/api';
import type { ActionEnum } from '#/enums/commonEnum';

import { h, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';

import { useAccess } from '@vben/access';
import { JsonViewer } from '@vben/common-ui';
import { $t } from '@vben/locales';

import { java } from '@codemirror/lang-java';
import { oneDark } from '@codemirror/theme-one-dark';
import { Badge } from 'ant-design-vue';

import { BaseOperationLogApi } from '#/api/basic/system/baseOperationLog';
import { DictEnum } from '#/enums/commonEnum';
import { PermCode } from '#/enums/perm';
import {
  backendDict,
  createdTimeColumn,
  deleteButton,
  indexColumn,
} from '#/plugins/fast-crud/common';

const logExtensions = [java(), oneDark];
const { hasPermission } = useAccess();
const permCode = PermCode.basic.system.baseOperationLog;

export function createCrudOptions(
  props: CreateCrudOptionsProps,
): CreateCrudOptionsRet {
  const selectedRowKeys = ref<string[]>([]);

  const STATUS_MAP = [
    { threshold: 100, status: 'success' },
    { threshold: 1000, status: 'warning' },
    { threshold: 10_000, status: 'error' },
  ];

  type BadgeStatus = 'default' | 'error' | 'processing' | 'success' | 'warning';
  // 获取状态值的函数
  const getStatus = (consumingTime: number): BadgeStatus => {
    for (const { threshold, status } of STATUS_MAP) {
      if (consumingTime < threshold) {
        return status as BadgeStatus;
      }
    }
    const curr = STATUS_MAP[STATUS_MAP.length - 1];
    return curr?.status as BadgeStatus;
  };

  return {
    crudOptions: {
      request: {
        pageRequest: BaseOperationLogApi.pageRequest,
        delRequest: BaseOperationLogApi.delRequest,
        infoRequest: BaseOperationLogApi.infoRequest,
      },
      actionbar: {
        buttons: {
          add: {},
          ...deleteButton({
            crudExpose: props.crudExpose,
            selectedRowKeys,
            role: permCode.delete,
            removeFn: BaseOperationLogApi.remove,
          }),
        },
      },
      table: {
        striped: true,
        rowKey: 'id',
        rowSelection: {
          type: 'checkbox',
          selectedRowKeys,
          onChange: (changed: string[]) => {
            selectedRowKeys.value = changed;
          },
        },
      },
      rowHandle: {
        width: '200px',
        buttons: {
          edit: { show: false },
          copy: { show: false },
          view: { show: hasPermission(permCode.view) },
          remove: { show: hasPermission(permCode.delete) },
        },
      },
      columns: {
        ...indexColumn(props.crudExpose),
        requestIp: {
          title: $t('basic.system.baseOperationLog.requestIp'),
          type: 'text',
          search: { show: true },
          column: { width: 170 },
        },
        type: {
          title: $t('basic.system.baseOperationLog.type'),
          type: 'dict-radio',
          dict: backendDict({ type: DictEnum.LogType }),
          column: { width: 80 },
          search: { show: true },
        },
        description: {
          title: $t('basic.system.baseOperationLog.description'),
          type: ['text', 'copyable'],
          column: { ellipsis: true, width: 200 },
        },
        classPath: {
          title: $t('basic.system.baseOperationLog.classPath'),
          type: 'text',
          column: { show: false },
        },
        actionMethod: {
          title: $t('basic.system.baseOperationLog.actionMethod'),
          type: 'text',
          column: {
            ellipsis: true,
            width: 200,
            formatter: (context: ScopeContext) => {
              return `${context.form.classPath}.${context.form.actionMethod}`;
            },
          },
        },
        requestUri: {
          title: $t('basic.system.baseOperationLog.requestUri'),
          type: 'text',
          column: { ellipsis: true, width: 200 },
        },
        httpMethod: {
          title: $t('basic.system.baseOperationLog.httpMethod'),
          type: 'dict-radio',
          column: { width: 80 },
          dict: backendDict({ type: DictEnum.HttpMethod }),
          search: { show: true },
        },
        params: {
          title: '参数',
          type: 'text',
          viewForm: { ignoreUseCellComponent: true },
          form: {
            col: {
              span: 24,
            },
            render: (scope: ScopeContext) => {
              try {
                const json = JSON.parse(scope.form.params);
                if (json) {
                  return (
                    <JsonViewer boxed copyable expand-depth="3" value={json} />
                  );
                }
                return h('div', scope.form.params);
              } catch {
                return h('div', scope.form.params);
              }
            },
          },
          column: { show: false },
        },
        result: {
          title: '返回结果',
          type: 'json',
          viewForm: { ignoreUseCellComponent: true },
          form: {
            col: {
              span: 24,
            },
            valueBuilder({ form }: ValueBuilderContext) {
              if (form.result === null) {
                return;
              }
              form.result = JSON.parse(form.result);
            },
            valueResolve({ form }: ValueResolveContext) {
              if (form.result === null) {
                return;
              }
              form.result = JSON.stringify(form.result);
            },
          },
          column: { show: false },
        },
        exDetail: {
          title: '异常日志',
          type: 'text',
          viewForm: { ignoreUseCellComponent: true },
          form: {
            col: {
              span: 24,
            },
            render: (scope: ScopeContext) => {
              return h(Codemirror, {
                autofocus: true,
                extensions: logExtensions,
                indentWithTab: true,
                style: { height: '200px' },
                tabSize: 2,
                modelValue: scope.form.exDetail,
              });
            },
          },
          column: { show: false },
        },
        startTime: {
          title: $t('basic.system.baseOperationLog.startTime'),
          type: 'datetime',
          column: { width: 170 },
          form: {
            component: {
              format: 'YYYY-MM-DD HH:mm:ss',
              valueFormat: 'YYYY-MM-DD HH:mm:ss',
            },
          },
          valueBuilder({ value, row, key }) {
            if (value !== null) {
              row[key] = value;
            }
          },
        },
        finishTime: {
          title: $t('basic.system.baseOperationLog.finishTime'),
          type: 'datetime',
          column: { width: 170 },
          form: {
            component: {
              format: 'YYYY-MM-DD HH:mm:ss',
              valueFormat: 'YYYY-MM-DD HH:mm:ss',
            },
          },
          valueBuilder({ value, row, key }) {
            if (value !== null) {
              row[key] = value;
            }
          },
        },
        consumingTime: {
          title: $t('basic.system.baseOperationLog.consumingTime'),
          type: 'text',
          column: {
            width: 100,
            cellRender: (scope: ScopeContext) => {
              const consumingTime = scope.form.consumingTime;

              const status = getStatus(consumingTime);
              return [
                h(Badge, {
                  dot: true,
                  status,
                  text: ` ${consumingTime}ms`,
                }),
              ];
            },
          },
        },
        ua: {
          title: $t('basic.system.baseOperationLog.ua'),
          type: 'textarea',
          search: { show: true },
          column: { width: 100, ellipsis: true },
        },
        ...createdTimeColumn({}),
      },
    },
  };
}

export const frontRules = (
  _crudExpose: CrudExpose,
  _mode: ActionEnum,
): FormRulesExt => {
  return {};
};
